fix(rename): avoid hitting runtime assert when renaming virtual files
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Wed, 23 Apr 2025 16:26:54 +0000 (18:26 +0200)
committerMatthieu Gallien <matthieu.gallien@nextcloud.com>
Thu, 24 Apr 2025 09:51:24 +0000 (11:51 +0200)
when propagating a rename to the child items, we must not make child
items be done from propagator point of view

they will be part of their own propagator item and that will create
issues

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
src/libsync/propagatorjobs.cpp
test/testsynccfapi.cpp

index 59b7ec9c98dfacfe8b6d7ae11cd12a6be0a6f284..6711685a31a3fc240683106e3df03b990374f686 100644 (file)
@@ -490,12 +490,10 @@ void PropagateLocalRename::start()
             SyncJournalFileRecord oldRecord;
             if (!propagator()->_journal->getFileRecord(oldFileNameString, &oldRecord)) {
                 qCWarning(lcPropagateLocalRename) << "Could not get file from local DB" << oldFileNameString;
-                done(SyncFileItem::NormalError, tr("Could not get file %1 from local DB").arg(oldFileNameString), OCC::ErrorCategory::GenericError);
                 return;
             }
             if (!propagator()->_journal->deleteFileRecord(oldFileNameString)) {
                 qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << oldFileNameString;
-                done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(oldFileNameString), OCC::ErrorCategory::GenericError);
                 return;
             }
 
@@ -503,7 +501,6 @@ void PropagateLocalRename::start()
             newItem->_file = newFileNameString;
             const auto result = propagator()->updateMetadata(*newItem);
             if (!result) {
-                done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), OCC::ErrorCategory::GenericError);
                 return;
             }
         });
index 20f509cb64aa99aa1c737fcf5efced2a96568d1a..b34b480c0c14de871fd171f030e8e8f0241bdb50 100644 (file)
@@ -1486,6 +1486,35 @@ private slots:
         QVERIFY(itemInstruction(completeSpy, odtFile, CSYNC_INSTRUCTION_UPDATE_METADATA));
         QCOMPARE(*vfs->pinState(odtFile), PinState::Unspecified);
     }
+
+    void renameOnBothSides()
+    {
+        FakeFolder fakeFolder { FileInfo::A12_B12_C12_S12() };
+        auto vfs = setupVfs(fakeFolder);
+
+        // Test that renaming a file within a directory that was renamed on the other side actually do a rename.
+
+        // 1) move the folder alphabetically before
+        fakeFolder.remoteModifier().rename("A/a1", "A/a1m");
+        fakeFolder.localModifier().rename("A", "_A");
+        fakeFolder.localModifier().rename("B/b1", "B/b1m");
+        fakeFolder.remoteModifier().rename("B", "_B");
+
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentRemoteState(), fakeFolder.currentRemoteState());
+        QVERIFY(fakeFolder.currentRemoteState().find("_A/a1m"));
+        QVERIFY(fakeFolder.currentRemoteState().find("_B/b1m"));
+
+        // 2) move alphabetically after
+        fakeFolder.remoteModifier().rename("_A/a2", "_A/a2m");
+        fakeFolder.localModifier().rename("_B/b2", "_B/b2m");
+        fakeFolder.localModifier().rename("_A", "S/A");
+        fakeFolder.remoteModifier().rename("_B", "S/B");
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentRemoteState(), fakeFolder.currentRemoteState());
+        QVERIFY(fakeFolder.currentRemoteState().find("S/A/a2m"));
+        QVERIFY(fakeFolder.currentRemoteState().find("S/B/b2m"));
+    }
 };
 
 QTEST_GUILESS_MAIN(TestSyncCfApi)